package br.com.iswe.gwt.crud.client;

import java.util.List;

import br.com.iswe.core.entidades.gwt.BeanMap;
import br.com.iswe.gwt.ui.client.BeanMapFormFactory;
import br.com.iswe.gwt.ui.client.Listener;
import br.com.iswe.gwt.ui.client.ListenerCollection;
import br.com.iswe.gwt.ui.client.MessagePanel;
import br.com.iswe.gwt.ui.client.ModalDialogBox;
import br.com.iswe.gwt.ui.client.PopupValidationHandler;
import br.com.iswe.gwt.ui.client.QueryInfo;
import br.com.iswe.gwt.ui.client.RequestInfo;
import br.com.iswe.gwt.ui.client.ValidationHandlerImpl;
import br.com.iswe.gwt.ui.client.service.BeanMapServiceClientImpl;

import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.FocusWidget;

public abstract class BeanMapDetailPanel extends DetailsPanelAbstract<BeanMap> implements DetailPanelContract<BeanMap> {
	
	public BeanMapDetailPanel(){}
	
	protected BeanMapFormFactory formFactory = new BeanMapFormFactory(new PopupValidationHandler(), new ValidationHandlerImpl());
	public BeanMapFormFactory getFormFactory() {
		return formFactory;
	}

	protected abstract String getIdProperty();
	
	protected abstract BeanMapServiceClientImpl getService();
	
	protected abstract void setupScreen();
	
	protected void populate(BeanMap bean){
		formFactory.populateFormProperties(bean);
	}
	
	private ListenerCollection<DetailPanelContract<BeanMap>> cancelListener = new ListenerCollection<DetailPanelContract<BeanMap>>();
	private ListenerCollection<DetailPanelContract<BeanMap>> afterSaveListener = new ListenerCollection<DetailPanelContract<BeanMap>>();
	private ListenerCollection<DetailPanelContract<BeanMap>> afterDeleteListener = new ListenerCollection<DetailPanelContract<BeanMap>>();
	private ListenerCollection<DetailPanelContract<BeanMap>> afterDetailListener = new ListenerCollection<DetailPanelContract<BeanMap>>();
	
	protected void cancelClose() {
		cancelListener.fire(this);
	}
	
	protected void afterDetail() {
		afterDetailListener.fire(this);
	}
	
	protected void errorOnSave(Throwable caught) {
		MessagePanel.getInstance().showError(caught, "Error saving the record!");
		if(getSaveButton() != null){
			getSaveButton().setEnabled(true);
		}
	}
	
	protected void afterSave(BeanMap bean) {
		//popula o formFactory com os dados modificados
		populate(bean);
		//show the success message
		MessagePanel.getInstance().showMessage("Record saved successfully !");
		//
		if(getSaveButton() != null){
			getSaveButton().setEnabled(true);
		}
		//
		afterSaveListener.fire(this);
	}
	
	protected BeanMap beforeSave() {
		BeanMap beanMap = formFactory.getMapValues();
		if(getSaveButton() != null){
			getSaveButton().setEnabled(false);
		}
		return beanMap;
	}
	
	protected abstract RequestInfo getRequestInfoSave();
	
	protected void notValidOnSave(){
		if(getSaveButton() != null){
			getSaveButton().setEnabled(true);
		}
	}
	
	protected void delete(){
		BeanMap beanMap = beforeDelete();		
		getService().deletar(beanMap, new AsyncCallback<BeanMap>(){
			public void onFailure(Throwable caught) {
				errorOnDelete(caught);
			}
			public void onSuccess(BeanMap beanMap) {
				afterDelete();
			}
		});
	}
	
	protected BeanMap beforeDelete() {
		BeanMap filter = new BeanMap();
		filter.put(getIdProperty(), getFormFactory().getMapValues().getString(getIdProperty()));
		if(getDeleteButton() != null){
			getDeleteButton().setEnabled(false);
		}
		return filter;
	}
	
	protected void afterDelete() {
		MessagePanel.getInstance().showMessage("Record deleted successfully !");
		if(getDeleteButton() != null){
			getDeleteButton().setEnabled(true);
		}
		afterDeleteListener.fire(this);
	}
	
	protected void errorOnDelete(Throwable caught) {
		MessagePanel.getInstance().showError(caught, "Error deleting the record!");
		if(getDeleteButton() != null){
			getDeleteButton().setEnabled(true);
		}
	}

	protected void save(){
		BeanMap beanMap = beforeSave();
		
		if( ! validate() ){
			notValidOnSave();
			return;
		}
		
		getService().salvar(beanMap, new AsyncCallback<BeanMap>(){
			public void onFailure(Throwable caught) {
				errorOnSave(caught);
			}
			public void onSuccess(BeanMap bean) {
				afterSave(bean);
			}}, 
			getRequestInfoSave());
	}
	
	protected boolean validate(){
		return formFactory.validate();
	}

	protected abstract QueryInfo getQueryInfoDetail();
	
	protected BeanMap beforeDetail(BeanMap bean) {
		BeanMap filter = new BeanMap();
		filter.put(getIdProperty(), bean.getString(getIdProperty()));
		
		//clear the message panel
		MessagePanel.getInstance().clearPanel();
		
		return filter;
	}
	
	public void detail(BeanMap beanMap) {
		//Detalha o registro
		//cria um novo mapa contendo apenas o id da entidade
		BeanMap filter = beforeDetail(beanMap);
		
		getService().detalhar(filter, getQueryInfoDetail(), new AsyncCallback<BeanMap>(){
			public void onFailure(Throwable caught) {
				MessagePanel.getInstance().showError(caught, "Error detail the record!");
			}
			public void onSuccess(BeanMap bean) {
				//popula o formFactory com os dados m
				populate(bean);
				afterDetail();
			}});
	}
	
	protected void showDetailPopup(BeanMapDetailPanel detailPanel, Listener<DetailPanelContract<BeanMap>> reloadMasterListener, String title){
		final ModalDialogBox modalPanel = new ModalDialogBox();
		//modalPanel.setText(title);
		modalPanel.setupDialogBox( title );
	
		modalPanel.setWidget( detailPanel  );
		modalPanel.show();
		
		Listener<DetailPanelContract<BeanMap>> closePopUpListener = new Listener<DetailPanelContract<BeanMap>>(){ 
			public void execute(DetailPanelContract<BeanMap> detailPanel) {
				modalPanel.hide();
		}};
		detailPanel.addCancelListener(closePopUpListener);
		detailPanel.addAfterSaveListener(closePopUpListener);
		detailPanel.addAfterSaveListener(reloadMasterListener);
		detailPanel.addAfterDeleteListener(reloadMasterListener);
		detailPanel.addAfterDeleteListener(closePopUpListener);
	}
	
	@SuppressWarnings("unchecked")
	protected void showSearchPanelAsPopup(SearchPanel searchPanel, QueryInfo queryInfoDetailList, BeanMap bean, BeanMapServiceClientImpl manyToManyService, String title) {
		super.showSearchPanelAsPopup(searchPanel, queryInfoDetailList, bean, manyToManyService, title, new AsyncCallback<BeanMap>(){
			public void onFailure(Throwable caught) {
				MessagePanel.getInstance().showError(caught, "Error saving selected itens!");
			}
			public void onSuccess(BeanMap bean) {
				//popula a tela "master" com a lista q foi salva
				//popula com a nova versao da entidade
				populate(bean);
			}
		});
	}
	
	protected void removeFromDetailList(List<BeanMap> detailList, QueryInfo queryInfoDetailList, String property) {
		if(detailList.size() > 0){
			BeanMap bean = new BeanMap();
			bean.put( getIdProperty(), formFactory.getMapValues().getString( getIdProperty() ) );
			bean.put(PROPERTY, property);
			//lista
			bean.put(property, detailList);
			getService().removerManyToMany(bean, queryInfoDetailList, new AsyncCallback<BeanMap>(){
				public void onFailure(Throwable caught) {
					MessagePanel.getInstance().showError(caught, "Error removing selected itens!");
				}
				public void onSuccess(BeanMap bean) {
					//popula a tela de usuario com a lista q foi salva
					//popula com a nova versao da entidade
					populate(bean);
				}});
		}
	}
	
	public void addAfterDetailListener(Listener<DetailPanelContract<BeanMap>> listener){
		afterDetailListener.add(listener);
	}
	
	public void addCancelListener(Listener<DetailPanelContract<BeanMap>> listener){
		cancelListener.add(listener);
	}
	
	public void addAfterSaveListener(Listener<DetailPanelContract<BeanMap>> listener){
		afterSaveListener.add(listener);
	}
	
	public void addAfterDeleteListener(Listener<DetailPanelContract<BeanMap>> listener){
		afterDeleteListener.add(listener);
	}

	public BeanMap getEntity(){
		return getFormFactory().getMapValues();
	}

	protected FocusWidget getSaveButton(){return null;}
	
	protected FocusWidget getDeleteButton(){return null;}
	
	public void prepareInsert(){
		if(getDeleteButton() != null){
			getDeleteButton().setEnabled(false);
		}
	}
	
}
